#include <yatak/kheap.h>
#include <libc/math.h>
#include <yatak/rsa.h>

CRsa::CRsa(int ps, int qs)
{
	GenerateKeys (FindEasyNumber(ps),FindEasyNumber(qs));
	m_code = 0;
	m_decode = 0;
	m_size = 0;
}

CRsa::CRsa(char* decode, int size, int ps, int qs)
{
	GenerateKeys (FindEasyNumber(ps),FindEasyNumber(qs));
	m_size = size;
	m_code = 0;
	//m_decode = new char [size];
	m_decode = (char *)kmalloc (sizeof(char)*size);
	for (int i = 0; i < size; i++)
		m_decode [i] = decode [i];
}

CRsa::CRsa(int* code, int size, int ps, int qs)
{
	GenerateKeys (FindEasyNumber(ps),FindEasyNumber(qs));
	m_size = size;
	//m_code = new int [size];
	m_code = (int *) kmalloc (sizeof (int)*size);
	for (int i = 0; i < size; i++)
		m_code [i] = code [i];
	m_decode = 0;
}

CRsa::~CRsa()
{
	if (m_code)
		//delete [] m_code;
		kfree (m_code);
	if (m_decode)
		//delete [] m_decode;
		kfree (m_decode);
}

long long unsigned int CRsa::PowerMod(long long unsigned int a, long long unsigned int b, long long unsigned int c)
{
	//a%=c;
	a = a- ((int)((double)a/(double)c))*c;
	unsigned long long res = 1;
	while (b) 
	{
		if (b & 1) 
			res = res*a - ((unsigned long long)((double)(res*a)/(double)c))*c;
			//res =(res*a)%c;
		a = a*a - ((unsigned long long)((double)(a*a)/(double)c))*c;
		//a=(a*a)%c;
		b >>= 1;
	}
	return res;
	//return (b==0) ? 1%c :
	//	( a%=c, (b & 1) ? (a*PowerMod(a,b>>1,c))%c :
	//		PowerMod(a*a,b>>1,c)
	//	);
}

void CRsa::GenerateKeys(long long unsigned int p, long long unsigned int q)
{
	// Вычислю модуль
	unsigned long long n = p*q;
	// Вычислю формулу Эйлера
	unsigned long long yn = (p-1)*(q-1);
	// Выберем случайное число, которое назовем d. Это число должно 
	// быть взаимно простым (не иметь ни одного общего делителя, 
	// кроме 1) с результатом умножения (p-1)*(q-1).
	unsigned long long d = EasyNumberWith (3,yn);
	// Определим такое число е, для которого является истинным
	// следующее соотношение (e*d) mod ((p-1)*(q-1))=1.
	unsigned long long e = FindE (3,d,yn);
	
	m_open_key [0] = e;
	m_open_key [1] = n;
	m_close_key [0] = d;
	m_close_key [1] = n;
}

long long unsigned int CRsa::EasyNumberWith(long long unsigned int start, long long unsigned int with)
{
	unsigned long long res = 0;
	while (1)
	{
		res = MersenneNumber(start);
		//if ((res%with) && (with%res))
		if ((res- ((int)((double)res/(double)with))*with) && (with- ((int)((double)with/(double)res))*res))
			break;
		start++;
	}
	return res;
}

long long unsigned int CRsa::MersenneNumber(int n)
{
	return (pow (2,n)-1);
}

long long unsigned int CRsa::FindEasyNumber(long long unsigned int start)
{
	// This function in the future must find easy numbers
	//return start;
	return MersenneNumber(start);
}

long long unsigned int CRsa::FindE(long long unsigned int start, long long unsigned int d, long long unsigned int yn)
{
	unsigned long long res = start;
	while (1)
	{
		unsigned long long tmp = res*d;
		//tmp = tmp % yn;
		tmp = tmp - ((int)((double)tmp/(double)yn))*yn;
		if (tmp == 1)
			break;
		res++;
	}
	return res;
}

int CRsa::GetSize()
{
	return m_size;
}

int* CRsa::GetCodeMsg()
{
	return m_code;
}

char* CRsa::GetDecodeMsg()
{
	return m_decode;
}

void CRsa::SetCodeMsg(int* code, int size)
{
	if (m_code)
	{
		kfree (m_code);
		//delete [] m_code;
		m_code = 0;
	}
	if (m_decode)
	{
		kfree (m_decode);
		//delete [] m_decode;
		m_decode = 0;
	}
	m_size = size;
	//m_code = new int [size];
	m_code = (int *)kmalloc (sizeof(int)*size);
	for (int i = 0; i < size; i++)
		m_code [i] = code [i];
}

void CRsa::SetDecodeMsg(char* decode, int size)
{
	if (m_code)
	{
		kfree (m_code);
		//delete [] m_code;
		m_code = 0;
	}
	if (m_decode)
	{
		kfree (m_decode);
		//delete [] m_decode;
		m_decode = 0;
	}
	m_size = size;
	//m_decode = new char [size];
	m_decode = (char *)kmalloc (sizeof(char)*size);
	for (int i = 0; i < size; i++)
		m_decode [i] = decode [i];
}

void CRsa::coder()
{
	if (!m_decode)
		return;
	if (m_code)
		kfree (m_code);
		//delete [] m_code;
	//m_code = new int [m_size];
	m_code = (int *)kmalloc(sizeof(int)*m_size);
	for (int i = 0; i < m_size; i++)
		m_code [i] = (int)PowerMod((int)m_decode[i],m_open_key[0],m_open_key[1]);
}

void CRsa::decoder()
{
	if (!m_code)
		return;
	if (m_decode)
		kfree (m_decode);
		//delete [] m_decode;
	//m_decode = new char [m_size];
	m_decode = (char *)kmalloc (sizeof(char)*m_size);
	for(int i = 0; i < m_size; i++)
		m_decode [i] = (char)PowerMod((int)m_code[i],m_close_key[0],m_close_key[1]);
}

int * codeRsaMsg (char *msg, int size)
{
	CRsa code (msg,size);
	int * res;
	code.coder();
	int * tmp = code.GetCodeMsg();
	//res = new int [size];
	res = (int *)kmalloc (sizeof(int)*size);
	for (int i = 0; i < size; i++)
		res [i] = tmp [i];
	return res;
}

char * decodeRsaMsg (int * msg, int size)
{
	CRsa decode;
	char * res;
	decode.SetCodeMsg(msg,size);
	decode.decoder();
	char * tmp = decode.GetDecodeMsg();
	//res = new char [size];
	res = (char *)kmalloc (sizeof(char)*size);
	for (int i = 0; i < size; i++)
		res [i] = tmp [i];
	return res;
}